Fix unmask_evtchn() when the port is bound to a different
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 13 Dec 2005 18:20:29 +0000 (19:20 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 13 Dec 2005 18:20:29 +0000 (19:20 +0100)
VCPU.

Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
linux-2.6-xen-sparse/include/asm-xen/evtchn.h
xen/common/event_channel.c
xen/include/public/event_channel.h
xen/include/xen/event.h

index 7ebe3f5e5840858eefd1a18d4f9acdad094fd5ee..b57116d3ea2d456ba601b6d426a0653b70d9db10 100644 (file)
@@ -639,6 +639,44 @@ void notify_remote_via_irq(int irq)
 }
 EXPORT_SYMBOL(notify_remote_via_irq);
 
+void mask_evtchn(int port)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       synch_set_bit(port, &s->evtchn_mask[0]);
+}
+EXPORT_SYMBOL(mask_evtchn);
+
+void unmask_evtchn(int port)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       unsigned int cpu = smp_processor_id();
+       vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
+
+       /* Slow path (hypercall) if this is a non-local port. */
+       if (unlikely(cpu != cpu_from_evtchn(port))) {
+               evtchn_op_t op = { .cmd = EVTCHNOP_unmask,
+                                  .u.unmask.port = port };
+               (void)HYPERVISOR_event_channel_op(&op);
+               return;
+       }
+
+       synch_clear_bit(port, &s->evtchn_mask[0]);
+
+       /*
+        * The following is basically the equivalent of 'hw_resend_irq'. Just
+        * like a real IO-APIC we 'lose the interrupt edge' if the channel is
+        * masked.
+        */
+       if (synch_test_bit(port, &s->evtchn_pending[0]) && 
+           !synch_test_and_set_bit(port / BITS_PER_LONG,
+                                   &vcpu_info->evtchn_pending_sel)) {
+               vcpu_info->evtchn_upcall_pending = 1;
+               if (!vcpu_info->evtchn_upcall_mask)
+                       force_evtchn_callback();
+       }
+}
+EXPORT_SYMBOL(unmask_evtchn);
+
 void irq_resume(void)
 {
        evtchn_op_t op;
index 788e8d7b5ec78f9ccc3244bd2da2adf83db26639..8c573b13e01f66a4fbad72885f080b18ab0e5e07 100644 (file)
@@ -79,46 +79,16 @@ extern int bind_ipi_to_irqhandler(
  */
 extern void unbind_from_irqhandler(unsigned int irq, void *dev_id);
 
-/*
- * Unlike notify_remote_via_evtchn(), this is safe to use across
- * save/restore. Notifications on a broken connection are silently dropped.
- */
-void notify_remote_via_irq(int irq);
-
 extern void irq_resume(void);
 
 /* Entry point for notifications into Linux subsystems. */
 asmlinkage void evtchn_do_upcall(struct pt_regs *regs);
 
 /* Entry point for notifications into the userland character device. */
-void evtchn_device_upcall(int port);
+extern void evtchn_device_upcall(int port);
 
-static inline void mask_evtchn(int port)
-{
-       shared_info_t *s = HYPERVISOR_shared_info;
-       synch_set_bit(port, &s->evtchn_mask[0]);
-}
-
-static inline void unmask_evtchn(int port)
-{
-       shared_info_t *s = HYPERVISOR_shared_info;
-       vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()];
-
-       synch_clear_bit(port, &s->evtchn_mask[0]);
-
-       /*
-        * The following is basically the equivalent of 'hw_resend_irq'. Just
-        * like a real IO-APIC we 'lose the interrupt edge' if the channel is
-        * masked.
-        */
-       if (synch_test_bit(port, &s->evtchn_pending[0]) && 
-           !synch_test_and_set_bit(port / BITS_PER_LONG,
-                                   &vcpu_info->evtchn_pending_sel)) {
-               vcpu_info->evtchn_upcall_pending = 1;
-               if (!vcpu_info->evtchn_upcall_mask)
-                       force_evtchn_callback();
-       }
-}
+extern void mask_evtchn(int port);
+extern void unmask_evtchn(int port);
 
 static inline void clear_evtchn(int port)
 {
@@ -134,6 +104,12 @@ static inline void notify_remote_via_evtchn(int port)
        (void)HYPERVISOR_event_channel_op(&op);
 }
 
+/*
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently dropped.
+ */
+extern void notify_remote_via_irq(int irq);
+
 #endif /* __ASM_EVTCHN_H__ */
 
 /*
index c3ef30ce34a5701c803ccd35e06334835a60cdef..eeccc0e1602f5e2926b06c21a7cb08cb9564523e 100644 (file)
@@ -3,7 +3,7 @@
  * 
  * Event notifications from VIRQs, PIRQs, and other domains.
  * 
- * Copyright (c) 2003-2004, K A Fraser.
+ * Copyright (c) 2003-2005, K A Fraser.
  * 
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -541,6 +541,41 @@ static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
     return rc;
 }
 
+static long evtchn_unmask(evtchn_unmask_t *unmask)
+{
+    struct domain *d = current->domain;
+    shared_info_t *s = d->shared_info;
+    int            port = unmask->port;
+    struct vcpu   *v;
+
+    spin_lock(&d->evtchn_lock);
+
+    if ( unlikely(!port_is_valid(d, port)) )
+    {
+        spin_unlock(&d->evtchn_lock);
+        return -EINVAL;
+    }
+
+    v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
+
+    /*
+     * These operations must happen in strict order. Based on
+     * include/xen/event.h:evtchn_set_pending(). 
+     */
+    if ( test_and_clear_bit(port, &s->evtchn_mask[0]) &&
+         test_bit          (port, &s->evtchn_pending[0]) &&
+         !test_and_set_bit (port / BITS_PER_LONG,
+                            &v->vcpu_info->evtchn_pending_sel) &&
+         !test_and_set_bit (0, &v->vcpu_info->evtchn_upcall_pending) )
+    {
+        evtchn_notify(v);
+    }
+
+    spin_unlock(&d->evtchn_lock);
+
+    return 0;
+}
+
 long do_event_channel_op(evtchn_op_t *uop)
 {
     long rc;
@@ -602,6 +637,10 @@ long do_event_channel_op(evtchn_op_t *uop)
         rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
         break;
 
+    case EVTCHNOP_unmask:
+        rc = evtchn_unmask(&op.u.unmask);
+        break;
+
     default:
         rc = -ENOSYS;
         break;
index bb15a87b7d0ffa6616cc47a2745789100834a66f..03d2039cd37328caae673af2c053ce21d99a6feb 100644 (file)
@@ -164,6 +164,16 @@ typedef struct evtchn_bind_vcpu {
     uint32_t vcpu;
 } evtchn_bind_vcpu_t;
 
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask           9
+typedef struct evtchn_unmask {
+    /* IN parameters. */
+    evtchn_port_t port;
+} evtchn_unmask_t;
+
 typedef struct evtchn_op {
     uint32_t cmd; /* EVTCHNOP_* */
     union {
@@ -176,6 +186,7 @@ typedef struct evtchn_op {
         evtchn_send_t             send;
         evtchn_status_t           status;
         evtchn_bind_vcpu_t        bind_vcpu;
+        evtchn_unmask_t           unmask;
     } u;
 } evtchn_op_t;
 
index a8632eaf09e4e41b5fc5c25951db90163c1b3957..b3c7713679cb0a11ef041b1f339cd935ad81cace 100644 (file)
@@ -3,7 +3,7 @@
  * 
  * A nice interface for passing asynchronous events to guest OSes.
  * 
- * Copyright (c) 2002, K A Fraser
+ * Copyright (c) 2002-2005, K A Fraser
  */
 
 #ifndef __XEN_EVENT_H__